package com.diaohw.module.websocket.service.ws;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.diaohw.module.websocket.obj.bo.WsOfflineBo;
import com.diaohw.module.websocket.service.MsgService;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

import static com.diaohw.module.websocket.config.WebsocketConfig.ONLINE_TIME;
import static com.diaohw.module.websocket.obj.enums.WSStatusEnums.*;
import static com.diaohw.module.websocket.service.ws.MessageHandle.SubscribeMap;
import static com.diaohw.module.websocket.service.ws.MessageHandle.getToken;

/**
 * @author 刁海文
 * @Desc 浏览器websocket链接
 */
@Slf4j
@Service
@ServerEndpoint("/{topic}/{subscribeId}")
public class WebsocketListener {


    private final MsgService msgService = SpringUtil.getBean(MsgService.class);

    /**
     * 用户上线
     *
     * @param topic       topic
     * @param subscribeId subscribeId
     * @param session     session
     */
    @OnOpen
    public void online(@PathParam("topic") String topic, @PathParam("subscribeId") String subscribeId, Session session) throws IOException {

        synchronized (topic + subscribeId) {
            SubscribeMap.computeIfAbsent(topic, k -> new ConcurrentHashMap<>())
                    .computeIfAbsent(subscribeId, k -> new ArrayList<>()).add(session);
        }
        log.info("online topic:{}, subscribeId:{}", topic, subscribeId);

        String token = getToken(session);
        msgService.process(topic, subscribeId, ONLINE, "", token);

    }

    /**
     * 用户下线
     *
     * @param topic       topic
     * @param subscribeId subscribeId
     * @param session     session
     */
    @OnClose
    public void offline(@PathParam("topic") String topic, @PathParam("subscribeId") String subscribeId, Session session) {
        synchronized (topic + subscribeId) {
            boolean remove = SubscribeMap.get(topic).get(subscribeId).remove(session);
            if (SubscribeMap.get(topic).get(subscribeId).isEmpty()) {
                SubscribeMap.get(topic).remove(subscribeId);
            }
            if (SubscribeMap.get(topic).isEmpty()) {
                SubscribeMap.remove(topic);
            }
        }
        LocalDateTime onlineTime = (LocalDateTime) session.getUserProperties().get(ONLINE_TIME);
        LocalDateTime offlineTime = LocalDateTime.now();
        long seconds = LocalDateTimeUtil.between(onlineTime, offlineTime, ChronoUnit.SECONDS);

        log.info("offline topic:{}, subscribeId:{}, Online Time:{}, Offline Time:{}, seconds:{}", topic, subscribeId, onlineTime, offlineTime, seconds);
        String token = getToken(session);
        String of = WsOfflineBo.ofStr(onlineTime, offlineTime, seconds);
        msgService.process(topic, subscribeId, OFFLINE, of, token);

    }

    /**
     * 收到客户端消息后调用
     */
    @OnMessage
    public void onMessage(String message, @PathParam("topic") String topic, @PathParam("subscribeId") String subscribeId, Session session) {
        String token = getToken(session);
        msgService.process(topic, subscribeId, MESSAGE, message, token);
    }

    /**
     * 发生错误/异常时调用
     */
    @OnError
    public void onError(Throwable error, @PathParam("topic") String topic, @PathParam("subscribeId") String subscribeId, Session session) {
        String token = getToken(session);
        msgService.process(topic, subscribeId, ERROR, error.toString(), token);
    }


}
